﻿using Avalonia.Controls.Notifications;
using Avalonia.Threading;
using Digitalmes.Core.Remotes.QcReworks;
using Notification = Ursa.Controls.Notification;
using WindowNotificationManager = Ursa.Controls.WindowNotificationManager;

namespace Digitalmes.AvaloniaUI.ViewModels;

/// <summary>
/// 返工 ViewModel
/// </summary>
public sealed partial class ReworkViewModel : ViewModelBase, IDisposable
{
    private readonly CancellationTokenSource _cts = new();

    private readonly IServiceProvider _serviceProvider;
    private readonly IMessageQueue<SerialPortMessage> _messageQueue;

    private WindowNotificationManager? _notificationManager;

    /// <summary>
    /// 扫入的条码
    /// </summary>
    [ObservableProperty]
    private string? _barcode = string.Empty;

    /// <summary>
    /// 当前所在工序
    /// </summary>
    [ObservableProperty]
    private string? _station = string.Empty;

    /// <summary>
    /// 进站时间
    /// </summary>
    [ObservableProperty]
    private string? _inboundTime = string.Empty;

    /// <summary>
    /// 出站时间
    /// </summary>
    [ObservableProperty]
    private string? _outboundTime = string.Empty;

    /// <summary>
    /// 产品状态
    /// </summary>
    [ObservableProperty]
    private string? _status = string.Empty;

    /// <summary>
    /// 操作人
    /// </summary>
    [ObservableProperty]
    private string? _operator = string.Empty;

    /// <summary>
    /// 内容
    /// </summary>
    [ObservableProperty]
    private string? _content = string.Empty;

    /// <summary>
    /// 扫码日志记录
    /// </summary>
    [ObservableProperty]
    private ObservableCollection<LogMessage> _messageLogs = [];

    [RelayCommand]
    private async Task Query(CancellationToken cancellationToken)
    {
        // 延迟执行
        await Task.Delay(300, cancellationToken);

        if (string.IsNullOrWhiteSpace(Barcode))
        {
            Notice("条码为空", "请输入条码内容", NotificationType.Warning);
            Barcode = string.Empty;
            return;
        }

        await QueryAsync(Barcode, false);
    }

    [RelayCommand]
    private async Task Submit(CancellationToken cancellationToken)
    {
        // 延迟执行
        await Task.Delay(300, cancellationToken);

        if (string.IsNullOrWhiteSpace(Barcode))
        {
            Notice("条码为空", "请输入条码内容", NotificationType.Warning);
            Barcode = string.Empty;
            return;
        }

        try
        {
            // 提交业务逻辑
            var api = _serviceProvider.GetRequiredService<QcReworkRemoteApi>();
            var (ok, result, ex) = await api.ReworkAsync(new QcReworkInput
            {
                Sn = Barcode?.Trim(),
                Operator = Operator?.Trim(),
                Content = Content?.Trim(),
            });

            if (ok && result?.Code == 200)
            {
                Notice("提交成功", Barcode, NotificationType.Success);
                AddLog($"提交成功，零件码：{Barcode}");

                Barcode = string.Empty; // 提交后清空条码
                Station = string.Empty;
                InboundTime = string.Empty;
                OutboundTime = string.Empty;
                Status = string.Empty;
            }
            else
            {
                Notice("提交失败", Barcode, NotificationType.Error);
                AddLog($"提交失败，零件码：{Barcode}，错误：{(ok ? result?.Message : ex?.Message)}", NotificationType.Error);
            }
        }
        catch (Exception ex)
        {
            AddLog(ex.Message, NotificationType.Error);
            AddLog($"提交异常，零件码：{Barcode}，错误：{ex.Message}", NotificationType.Error);
        }
    }

    public ReworkViewModel(IServiceProvider serviceProvider, IMessageQueue<SerialPortMessage> messageQueue)
    {
        _serviceProvider = serviceProvider;
        _messageQueue = messageQueue;

        DaemonPolling();
    }

    /// <summary>
    /// 后台轮询操作
    /// </summary>
    private void DaemonPolling()
    {
        _ = Task.Run(async () =>
        {
            while (!_cts.IsCancellationRequested)
            {
                var message = await _messageQueue.DequeueAsync().ConfigureAwait(false);
                var barcode = message.Args.Content.Trim(['\r', '\n', (char)0x20]); // 去掉可能存在的回车、换行和空白符
                if (string.IsNullOrEmpty(barcode))
                {
                    continue;
                }

                await QueryAsync(barcode, true);
            }
        });
    }

    /// <summary>
    /// 查询条码信息
    /// </summary>
    private async Task QueryAsync(string barcode, bool useUIThread)
    {
        try
        {
            var api = _serviceProvider.GetRequiredService<QcReworkRemoteApi>();
            var (ok, result, ex) = await api.GetBarcodeInfoAsync(barcode);

            if (useUIThread)
            {
                Dispatcher.UIThread.Post(() =>
                {
                    ShowUI(barcode, ok, result?.Data, ex);
                });
            }
            else
            {
                ShowUI(barcode, ok, result?.Data, ex);
            }
        }
        catch (Exception ex)
        {
            AddLog($"扫码查询异常，零件码：{barcode}，错误：{ex.Message}", NotificationType.Error);
        }

        void ShowUI(string barcode, bool ok, QcReworkDto? dto, Exception? innerEx)
        {
            Barcode = barcode;
            Station = dto?.CurProcCode ?? string.Empty;
            InboundTime = dto?.InboundTime.ToString("yyyy-MM-dd HH:mm:ss") ?? string.Empty;
            OutboundTime = dto?.OutboundTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? string.Empty;
            Status = dto?.StatusDesc ?? string.Empty;

            if (ok)
            {
                if (dto != null)
                {
                    Notice("扫码查询", barcode, NotificationType.Information);
                    AddLog($"扫码查询，零件码：{barcode}");
                }
                else
                {
                    Notice("扫码查询", $"没有找到零件码 {barcode}", NotificationType.Warning);
                    AddLog($"扫码查询，零件码：{barcode}，消息：没有找到该零件码信息", NotificationType.Warning);
                }
            }
            else
            {
                Notice("扫码查询", "扫码查询错误", NotificationType.Warning);
                AddLog($"扫码查询错误，零件码：{barcode}，错误：{innerEx?.Message}", NotificationType.Error);
            }
        }
    }

    private void AddLog(string? message, NotificationType messageType = NotificationType.Information)
    {
        if (MessageLogs.Count > 32)
        {
            MessageLogs.RemoveAt(MessageLogs.Count - 1);
        }

        var msg = $"{DateTime.Now:MM/dd HH:mm:ss}\t{message}";
        var msgType = messageType switch
        {
            NotificationType.Warning => "Warning",
            NotificationType.Error => "Danger",
            _ => string.Empty,
        };
        MessageLogs.Insert(0, new LogMessage(msg, msgType));
    }

    /// <summary>
    /// 界面显示通知消息
    /// </summary>
    private void Notice(string? title, string? content, NotificationType notificationType)
    {
        AttemptAttachNotificationManager();

        _notificationManager?.Show(
            new Notification(title, content),
            notificationType,
            expiration: TimeSpan.FromSeconds(5),
            showClose: false,
            classes: ["Light"]);
    }

    private void AttemptAttachNotificationManager()
    {
        if (_notificationManager == null && TopLevel != null)
        {
            _notificationManager = new WindowNotificationManager(TopLevel)
            {
                Position = NotificationPosition.TopCenter,
                MaxItems = 3,
            };
        }
    }

    public void Dispose()
    {
        _cts.Cancel();
        _notificationManager?.Uninstall();
    }
}
